#include "Reflection/Type.h"
#include "Reflection/FunctionList.h"
#include "Reflection/NativeFunction.h"
#include "Reflection/TypeUtils.h"
#include "Reflection/StringSerializable.h"

CType* CGetType<CString>::operator()()
{
    class CUTF32StringType: public CType
    {


    public:
        CUTF32StringType()
            :CType(
                STypeID(U"U32String",true)
                , ETypeFlags::Basic | ETypeFlags::ScriptInner 
            )
        {
            Instancable=new CStringInstance();
            StringSerializable=new StringStringSerializable();

            Functions= new CFunctionList(this);
            {
                auto ToStringFunction = new CNativeFunction(Functions,U"ToString",this,{},{});
                ToStringFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                {
                    CString Value=**reinterpret_cast<const CString**>(InArgs[0].GetPointer());
                    return Value;
                });
                Functions->VirtualFunctionTable.Add(ToStringFunction->ID);
            }

            PostConstructFunction=[this]()
            {
                //get type of TVector<CString>
                CType* StringVectorType=WH::FindOrCreateVectorType(this);

                //add Split(CString)
                {
                    auto SplitFunction = new CNativeFunction(
                        Functions
                        ,U"Split"
                        ,StringVectorType
                        ,{this}
                        ,{});
                    SplitFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast<CString**>(InArgs[0].GetPointer());
                        CString* Delimiter=reinterpret_cast<CString*>(InArgs[1].GetPointer());
                        return Value->Split(*Delimiter);
                    });
                }

                //add Split(char32_t)
                {
                    auto SplitFunction = new CNativeFunction(
                        Functions
                        ,U"Split"
                        ,StringVectorType
                        ,{WH::TReflectionType<char32_t>::FindOrCreateType()}
                        ,{});
                    SplitFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        char32_t* Delimiter=reinterpret_cast< char32_t*>(InArgs[1].GetPointer());
                        return Value->Split(*Delimiter);
                    });
                }

                //add ToInt()
                {
                    auto ToIntFunction = new CNativeFunction(
                        Functions
                        ,U"ToInt"
                        ,WH::TReflectionType<int64_t>::FindOrCreateType()
                        ,{}
                        ,{});
                    ToIntFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        return Value->ToInt64();
                    });
                }

                //add ToBool()
                {
                    auto ToBoolFunction = new CNativeFunction(
                        Functions
                        ,U"ToBool"
                        ,WH::TReflectionType<bool>::FindOrCreateType()
                        ,{}
                        ,{});
                    ToBoolFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        return Value->ToBool();
                    });
                }

                //add ToFloat()
                {
                    auto ToFloatFunction = new CNativeFunction(
                        Functions
                        ,U"ToFloat"
                        ,WH::TReflectionType<float>::FindOrCreateType()
                        ,{}
                        ,{});
                    ToFloatFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        return (float)Value->ToDouble();
                    });
                }

                //add ToDouble()
                {
                    auto ToDoubleFunction = new CNativeFunction(
                        Functions
                        ,U"ToDouble"
                        ,WH::TReflectionType<double>::FindOrCreateType()
                        ,{}
                        ,{});
                    ToDoubleFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        return Value->ToDouble();
                    });
                }

                //add GetLength()
                {
                    auto GetLengthFunction = new CNativeFunction(
                        Functions
                        ,U"GetLength"
                        ,WH::TReflectionType<int64_t>::FindOrCreateType()
                        ,{}
                        ,{});
                    GetLengthFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        return (int64_t)Value->GetLength();
                    });
                }

                //add GetCharAt(int64_t)
                {
                    auto GetCharAtFunction = new CNativeFunction(
                        Functions
                        ,U"GetCharAt"
                        ,WH::TReflectionType<char32_t>::FindOrCreateType()
                        ,{WH::TReflectionType<int64_t>::FindOrCreateType()}
                        ,{});
                    GetCharAtFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
                    {
                        CString* Value=*reinterpret_cast< CString**>(InArgs[0].GetPointer());
                        int64_t* Index=reinterpret_cast< int64_t*>(InArgs[1].GetPointer());
                        return Value->GetCharAt(*Index);
                    });
                }
            };
        }

    protected:
        class CStringInstance : public ITypeInstance
        {
        public:

            virtual uint32_t GetSize() override
            {
                return sizeof(CString);
            }

            void InitInstance(void * InMemory) override
            {
                new(InMemory) CString;
            }

            void EraseInstance(void * Instance) override
            {
                reinterpret_cast<CString*>(Instance)-> ~CString() ;
            }

            void CloneInstance(const void * Instance, void * Memory) override
            {
                new (Memory) CString(*reinterpret_cast<const CString*>(Instance));
            }

            uint64_t GetInstanceHash(const void * Instance) const override
            {
                return reinterpret_cast<const CString*>(Instance)->GetHashCode();
            }

            virtual bool IsInstanceEqual(const void * Instance0,const void * Instance1) const override
            {
                return *reinterpret_cast<const CString*>(Instance0)==*reinterpret_cast<const CString*>(Instance1);
            }

            void * CreateInstance() override
            {
                return new CString();
            }

            void ResetAllocated(void * Memory) override
            {
                reinterpret_cast<CString*>(Memory)->Clear();
            }

            CString ToDebugString(const void* InInstance) const override
            {
                return U"\""+ *reinterpret_cast<const CString*>(InInstance)+U"\"";
            }
        };

        class StringStringSerializable: public IStringSerializable
        {
        public:
            virtual CString ToString(const void* Instance) const override
            {
                return *reinterpret_cast<const CString*>(Instance);
            }
            virtual void FromString(const CString& InString,void * InInstance) const override
            {
                *reinterpret_cast<CString*>(InInstance)=InString;
            }
        };
    };

    static CType* Type=new CUTF32StringType();
    return Type;
};